home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 121_01 / plot.c < prev    next >
Text File  |  1985-08-19  |  10KB  |  341 lines

  1. /*
  2. HEADER: CUG 121.??;
  3.  
  4.     TITLE:    plot - an epson plottingg package;
  5.     VERSION:    1.0;
  6.     DATE:    01/10/86;
  7.     DESCRIPTION: "This program reads an input file of plot points and sends
  8.         commands to an epson-like printer to plot these points via
  9.         the graphics modes.
  10.         This program contains useful general-purpose plot routines
  11.         which could be extracted to form a library.";
  12.     KEYWORDS:    plot, graphics, epson;
  13.     SYSTEM:    CP/M;
  14.     FILENAME:    PLOT.C;
  15.     WARNINGS:    "Copyright (c) 1982, JTL Computer Services.
  16.         Requires local.h & plot.h for compile.
  17.         Requires local.c for link.
  18.         Requires Epson MX-80 with Graftrax.";
  19.     SEE-ALSO:    PLOT.H (header file), PLOT.DAT (sample data file);
  20.     AUTHORS:    Mike W. Meyer;
  21.     COMPILERS:    BDS-C 1.50;
  22. */
  23. /*
  24.  * plot - a package to use the dot-matrix abilities of the Epson
  25.  *    mx-80 line of printers.
  26.  *
  27.  */
  28.  
  29. #include <bdscio.h>
  30. #include "local.h"
  31. #include "plot.h"
  32.  
  33. /*
  34.  * section the first - the general plot manipulation routines.
  35.  *    initialize & print plots.
  36.  */
  37.  
  38. /*
  39.  * initplot - zero out everything in the plot...
  40.  */
  41. initplot(page, x, y) plot *page; {
  42.     int    i, j ;
  43.     plotline *line ;
  44.  
  45.     page -> p_x = page -> p_y = 0 ;
  46.     page -> p_xmax = min(x, LINELEN) ;
  47.     page -> p_ymax = min(y, PAGELEN) ;
  48.     line = page -> p_page ;
  49.     for (i = 0; i < PLEN; line++) {
  50.         line -> p_points = line -> p_text = NULL ;
  51.         page -> p_symtab[i++] . s_def = FALSE ;
  52.         }
  53.     }
  54. /*
  55.  * printplot - output the plot to the printer
  56.  */
  57. printplot(page, file) plot *page; char *file; {
  58.     int    i, j, len, plen ;
  59.     plotline *line ;
  60.  
  61.     /* set up the epson so that it has the right line spacing */
  62.     fprintf(file, "%cP%cA%c\r", ESC, ESC, VDEN) ;
  63.     line = page -> p_page ;
  64.     plen = page -> p_ymax / VDEN + ((page -> p_ymax % VDEN) ? 1 : 0) ;
  65.     for (i = 0; i++ < plen; line++) {
  66.         if (line -> p_points) {
  67.             for (len = page -> p_xmax; len > 0; len--)
  68.                 if (line -> p_points[len - 1]) break ;
  69.             fprintf(file, LENSTR, ESC) ;
  70.             putc(len % 256, file) ;
  71.             putc(len / 256, file) ;
  72.             for (j = 0; j < len;)
  73.                 putc(line -> p_points[j++], file) ;
  74.             free(line -> p_points) ;
  75.             }
  76.         if (line -> p_text) {
  77.             fprintf(file, "\r%s", line -> p_text) ;
  78.             free(line -> p_text) ;
  79.             }
  80.         fputs("\n", file) ;
  81.         }
  82.     /* Now, put the epson back in the normal 6 lpi mode */
  83.     fprintf(file, "%cQ%c2", ESC, ESC) ;
  84.     }
  85. /*
  86.  * section the second - routines used to put characters on the page.
  87.  */
  88.  
  89. /*
  90.  * plots - put string on page at position x, y (or thereabouts. Printer
  91.  *    accuracy, you know).
  92.  */
  93. plots(page, x, y, string) char *string; plot *page; {
  94.     int i ;
  95.  
  96.     do
  97.         if (*string < 0x20) return ERROR ;
  98.         else if ((x = plotc(page, x, y, *string)) == ERROR)
  99.             return ERROR ;
  100.         while (*string++) ;
  101.     return OK ;
  102.     }
  103. /*
  104.  * plotc - plot the character/symbol at x, y (or thereabouts).
  105.  */
  106. plotc(page, x, y, c) plot *page; {
  107.     int i ;
  108.     plotline *line ;
  109.  
  110.     if (c > SYMSEP)        /* plotting a symbol... */
  111.         return (plotsym(page, x * CDEN * CLEN, y * VDEN / VDEN, c)
  112.             + CLEN) * CDEN * CLEN ;
  113.     else {            /* normal character */
  114.         if (!(line = page -> p_page[y / VDEN]) . p_text) {
  115.             if ((line -> p_text = alloc(CHARS + 1)) == ERROR)
  116.                 return ERROR ;
  117.             for (i = 0; i < CHARS;) line -> p_text[i++] = ' ' ;
  118.             line -> p_text[i] = NULL ;
  119.             }
  120.         line -> p_text[x = x * CDEN] = c ;
  121.         return (x + 1) * CLEN + 1 ;    /* + 1 to force new char */
  122.         }
  123.     }
  124. /*
  125.  * section the third - routines to manipulate symbols
  126.  */
  127.  
  128. /*
  129.  * makesym - create the symbol labeled symno for use on page.
  130.  */
  131. makesym(page, symno, symbol) plot *page; char *symbol; {
  132.     char    i ;
  133.     symtab    *sym ;
  134.  
  135.     if (!validsym(symno++)) return ERROR ;
  136.     (sym = &(page -> p_symtab[symno])) -> s_def = TRUE ;
  137.     for (i = 0; i < SYMLEN; i++)
  138.         sym -> s_symbol[i] = symbol[i] ;
  139.     }
  140. /*
  141.  * symbol - put an array of symbols on the plot page. X, y is the
  142.  *    lower left hand corner of the first symbol in the string.
  143.  */
  144. symbol(page, x, y, symbols) plot *page; char *symbols; {
  145.  
  146.     while (*symbols)
  147.         if ((x = plotsym(page, x, y, *symbols)) == ERROR)
  148.             return ERROR ;
  149.     }
  150. /*
  151.  * plotsym - put the symbol on the page. X, y is the lower left hand
  152.  *    corner of the symbol.
  153.  */
  154. plotsym(page, x, y, symno) plot *page; {
  155.     char i, j, byte ;
  156.  
  157.     if (!inbounds(x, y) || !validsym(symno--)) return ERROR ;
  158.     for (i = 0; i < SYMLEN;) {
  159.         byte = page -> p_symtab[symno] . s_symbol[i++] ;
  160.         for (j = 0; j < CHARLEN; j++, byte >>= 1)
  161.             if ((byte & 1) && on(page, x + i, y - j) == ERROR) 
  162.                 return ERROR ;
  163.         }
  164.     }
  165. /*
  166.  * validsym - tells whether or not symno is a valid symbol #. Used
  167.  *    internally.
  168.  */
  169. validsym(symno) {
  170.  
  171.     return symno <= MAXSYM && symno > 0 ;
  172.     }
  173. /*
  174.  * issym - tells whether or not symno is a defined symbol on page.
  175.  */
  176. issym(page, symno) plot *page; {
  177.  
  178.     return validsym(symno) && page -> p_symtab[symno] . s_def ;
  179.     }
  180. /*
  181.  * section the fourth - a couple of routines to draw lines of
  182.  *    various flavors
  183.  */
  184.  
  185. /*
  186.  * line - draw a line from point where we left the pen to x, y.
  187.  *    if pen is down (== 2), or move the pen if it is up (== 3).
  188.  */
  189. line(page, x, y, pen) plot *page; {
  190.     int on() ;
  191.  
  192.     return genline(page, x, y, pen, on) ;
  193.     }
  194. /*
  195.  * genline - generalized draw a line routine.  This works the same
  196.  *    as the line routine, except that it applies the routine toit
  197.  *    to each point that is on the line, if pen is down (== 2). It
  198.  *    just moves the pen if it is up (== 3).
  199.  *    Algorithm from CALGO (Collected Algorithms of the ACM, for those
  200.  *    of you not in ACM). Translated from the original scuzzy ALGOL to
  201.  *    reasonable ALGOL by J. Jones. Then implemented in C by mwm & J. Jones.
  202.  */
  203. genline(page, x, y, pen, toit) plot *page; int (*toit)(); {
  204.     int     adx, ady, xstep, ystep, xfarther, dsquare, mindelta ,
  205.         distance, zot ;
  206.  
  207.     if (pen == UP) {
  208.         page -> p_x = x; page -> p_y = y ;
  209.         return OK ;
  210.         }
  211.     adx = abs(page -> p_x - x) ;
  212.     ady = abs(page -> p_y - y) ;
  213.     xstep = sign(x - page -> p_x) ;
  214.     ystep = sign(y - page -> p_y) ;
  215.     xfarther = adx > ady  ;
  216.     dsquare = abs(adx - ady) ;
  217.     mindelta = min(adx, ady) ;
  218.     distance = adx + ady ;
  219.     for (zot = 0; distance > 0;) {
  220.         if (zot + zot < dsquare - mindelta) {
  221.             zot += mindelta ;
  222.             distance-- ;
  223.             if (xfarther) page -> p_x += xstep ;
  224.             else page -> p_y += ystep ;
  225.             }
  226.         else {
  227.             zot -= dsquare ;
  228.             distance -= 2 ;
  229.             page -> p_x += xstep ;
  230.             page -> p_y += ystep ;
  231.             }
  232.         (*toit)(page, page -> p_x, page -> p_y) ;
  233.         }
  234.     return OK ;
  235.     }
  236.  
  237. /*
  238.  * section the bottom - this section contains the bottom level routines
  239.  *    for manipulating the plot. These routines turn on & off points in
  240.  *    the page image, and etc.
  241.  */
  242.  
  243. /*
  244.  * on - turn on the point x, y in the plot page.
  245.  */
  246. on(page, x, y) plot *page; {
  247.  
  248.     if (!inbounds(page, x, y)) return ERROR ;
  249.     page -> p_page[y / VDEN] . p_points[x] |= 0x80 >> (y % VDEN) ;
  250.     return OK ;
  251.     }
  252. /*
  253.  * off - turn off the point x, y in the plot page off.
  254.  */
  255. off(page, x, y) plot *page; {
  256.  
  257.     if (!inbounds(page, x, y)) return ERROR ;
  258.     page -> p_page[y / VDEN] . p_points[x] &= ~(0x80 >> (y % VDEN)) ;
  259.     return OK ;
  260.     }
  261. /*
  262.  * toggle - change the point x, y on the plot page.
  263.  */
  264. toggle(page, x, y) plot *page; {
  265.  
  266.     if (!inbounds(page, x, y)) return ERROR ;
  267.      page -> p_page[y / VDEN] . p_points[x] ^= (0x80 >> (y % VDEN)) ;
  268.     return  OK ;
  269.     }
  270. /*
  271.  * ison - return whether or not the point at x, y is on in the plot page.
  272.  */
  273. ison(page, x, y) plot *page; {
  274.  
  275.     if (!inbounds(page, x, y)) return ERROR ;
  276.      return page -> p_page[y / VDEN] . p_points[x] & (0x80 >> (y % VDEN)) ;
  277.     }
  278. /*
  279.  * inbounds - used internally to tell if the point x, y is inbounds or not.
  280.  *    also allocates space if it is needed for that piece of the plot.
  281.  */
  282. inbounds(page, x, y) plot *page; {
  283.     int i ;
  284.     plotline *line ;
  285.  
  286.     if (y >= page -> p_ymax || y < 0 || x >= page -> p_xmax || x < 0)
  287.         return FALSE ;
  288.     if ((line = page -> p_page[y / VDEN]) -> p_points) return TRUE ;
  289.     if ((line -> p_points = alloc(page -> p_xmax)) == ERROR)
  290.         return FALSE ;
  291.     for (i = 0; i < page -> p_xmax;)
  292.         line -> p_points[i++] = NULL ;
  293.     return TRUE ;
  294.     }
  295. /*
  296.  * section the last ...
  297.  * main - a somewhat u